home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / qsound.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  12KB  |  524 lines

  1. /***************************************************************************
  2.  
  3.   Capcom System QSound(tm)
  4.   ========================
  5.  
  6.   Driver by Paul Leaman (paul@vortexcomputing.demon.co.uk)
  7.         and Miguel Angel Horna (mahorna@teleline.es)
  8.  
  9.   A 16 channel stereo sample player.
  10.  
  11.   QSpace position is simulated by panning the sound in the stereo space.
  12.  
  13.   Register
  14.   0     xxbb    xx = unknown bb = start high address
  15.   1     ssss    ssss = sample start address
  16.   2     pitch
  17.   3     unknown (always 0x8000)
  18.   4     loop offset from end address
  19.   5     end
  20.   6     master channel volume
  21.   7     not used
  22.   8     Balance (left=0x0110  centre=0x0120 right=0x0130)
  23.   9     unknown (most fixed samples use 0 for this register)
  24.  
  25.   Many thanks to CAB (the author of Amuse), without whom this probably would
  26.   never have been finished.
  27.  
  28.   If anybody has some information about this hardware, please send it to me
  29.   to mahorna@teleline.es or 432937@cepsz.unizar.es.
  30.   http://teleline.terra.es/personal/mahorna
  31.  
  32. ***************************************************************************/
  33.  
  34. #include <math.h>
  35. #include "driver.h"
  36.  
  37. /*
  38. Two Q sound drivers:
  39. DRIVER1 Based on the Amuse source
  40. DRIVER2 Miguel Angel Horna (mahorna@teleline.es)
  41. */
  42. #define QSOUND_DRIVER1      1
  43. /*
  44. I don't know whether this system uses 8 bit or 16 bit samples.
  45. If it uses 16 bit samples then the sample ROM loading macros need
  46. to be modified to work with non-intel machines.
  47. */
  48. #define QSOUND_8BIT_SAMPLES 1
  49.  
  50. /*
  51. Debug defines
  52. */
  53. #define LOG_WAVE    0
  54. #define LOG_QSOUND  0
  55.  
  56. /* Typedefs & defines */
  57.  
  58. #define QSOUND_DRIVER2 !QSOUND_DRIVER1
  59.  
  60. #if QSOUND_8BIT_SAMPLES
  61. /* 8 bit source ROM samples */
  62. typedef signed char QSOUND_SRC_SAMPLE;
  63. #define LENGTH_DIV 1
  64. #else
  65. /* 8 bit source ROM samples */
  66. typedef signed short QSOUND_SRC_SAMPLE;
  67. #define LENGTH_DIV 2
  68. #endif
  69.  
  70. #define QSOUND_CLOCKDIV 166             /* Clock divider */
  71. #define QSOUND_CHANNELS 16
  72. typedef INT16 QSOUND_SAMPLE;
  73.  
  74. struct QSOUND_CHANNEL
  75. {
  76.     int bank;       /* bank (x16)    */
  77.     int address;    /* start address */
  78.     int pitch;      /* pitch */
  79.     int reg3;       /* unknown (always 0x8000) */
  80.     int loop;       /* loop address */
  81.     int end;        /* end address */
  82.     int vol;        /* master volume */
  83.     int pan;        /* Pan value */
  84.     int reg9;       /* unknown */
  85.  
  86.     /* Work variables */
  87.     int key;        /* Key on / key off */
  88.  
  89. #if QSOUND_DRIVER1
  90.     int lvol;       /* left volume */
  91.     int rvol;       /* right volume */
  92.     int lastdt;     /* last sample value */
  93.     int offset;     /* current offset counter */
  94. #else
  95.     QSOUND_SRC_SAMPLE *buffer;
  96.     int factor;           /*step factor (fixed point 8-bit)*/
  97.     int mixl,mixr;        /*mixing factor (fixed point)*/
  98.     int cursor;           /*current sample position (fixed point)*/
  99.     int lpos;             /*last cursor pos*/
  100.     int lastsaml;         /*last left sample (to avoid any calculation)*/
  101.     int lastsamr;         /*last right sample*/
  102. #endif
  103. };
  104.  
  105.  
  106. /* Private variables */
  107. static struct QSound_interface *intf;    /* Interface  */
  108. static int qsound_stream;                /* Audio stream */
  109. static struct QSOUND_CHANNEL qsound_channel[QSOUND_CHANNELS];
  110. static int qsound_data;                  /* register latch data */
  111. QSOUND_SRC_SAMPLE *qsound_sample_rom;    /* Q sound sample ROM */
  112.  
  113. #if QSOUND_DRIVER1
  114. static int qsound_pan_table[33];         /* Pan volume table */
  115. static float qsound_frq_ratio;           /* Frequency ratio */
  116. #endif
  117.  
  118. #if LOG_WAVE
  119. static FILE *fpRawDataL;
  120. static FILE *fpRawDataR;
  121. #endif
  122.  
  123. /* Function prototypes */
  124. void qsound_update( int num, INT16 **buffer, int length );
  125. void qsound_set_command(int data, int value);
  126.  
  127. #if QSOUND_DRIVER2
  128. void setchannel(int channel,signed short *buffer,int length,int vol,int pan);
  129. void setchloop(int channel,int loops,int loope);
  130. void stopchan(int channel);
  131. void calcula_mix(int channel);
  132. #endif
  133.  
  134. int qsound_sh_start(const struct MachineSound *msound)
  135. {
  136.     int i;
  137.  
  138.     if (Machine->sample_rate == 0) return 0;
  139.  
  140.     intf = msound->sound_interface;
  141.  
  142.     qsound_sample_rom = (QSOUND_SRC_SAMPLE *)memory_region(intf->region);
  143.  
  144.     memset(qsound_channel, 0, sizeof(qsound_channel));
  145.  
  146. #if QSOUND_DRIVER1
  147.     qsound_frq_ratio = ((float)intf->clock / (float)QSOUND_CLOCKDIV) /
  148.                         (float) Machine->sample_rate;
  149.     qsound_frq_ratio *= 16.0;
  150.  
  151.     /* Create pan table */
  152.     for (i=0; i<33; i++)
  153.     {
  154.         qsound_pan_table[i]=(int)((256/sqrt(32)) * sqrt(i));
  155.     }
  156. #else
  157.     i=0;
  158. #endif
  159.  
  160. #if LOG_QSOUND
  161.     logerror("Pan table\n");
  162.     for (i=0; i<33; i++)
  163.         logerror("%02x ", qsound_pan_table[i]);
  164. #endif
  165.     {
  166.         /* Allocate stream */
  167. #define CHANNELS ( 2 )
  168.         char buf[CHANNELS][40];
  169.         const char *name[CHANNELS];
  170.         int  vol[2];
  171.         name[0] = buf[0];
  172.         name[1] = buf[1];
  173.         sprintf( buf[0], "%s L", sound_name(msound) );
  174.         sprintf( buf[1], "%s R", sound_name(msound) );
  175.         vol[0]=MIXER(intf->mixing_level[0], MIXER_PAN_LEFT);
  176.         vol[1]=MIXER(intf->mixing_level[1], MIXER_PAN_RIGHT);
  177.         qsound_stream = stream_init_multi(
  178.             CHANNELS,
  179.             name,
  180.             vol,
  181.             Machine->sample_rate,
  182.             0,
  183.             qsound_update );
  184.     }
  185.  
  186. #if LOG_WAVE
  187.     fpRawDataR=fopen("qsoundr.raw", "w+b");
  188.     fpRawDataL=fopen("qsoundl.raw", "w+b");
  189.     if (!fpRawDataR || !fpRawDataL)
  190.     {
  191.         return 1;
  192.     }
  193. #endif
  194.  
  195.     return 0;
  196. }
  197.  
  198. void qsound_sh_stop (void)
  199. {
  200.     if (Machine->sample_rate == 0) return;
  201. #if LOG_WAVE
  202.     if (fpRawDataR)
  203.     {
  204.         fclose(fpRawDataR);
  205.     }
  206.     if (fpRawDataL)
  207.     {
  208.         fclose(fpRawDataL);
  209.     }
  210. #endif
  211. }
  212.  
  213. WRITE_HANDLER( qsound_data_h_w )
  214. {
  215.     qsound_data=(qsound_data&0xff)|(data<<8);
  216. }
  217.  
  218. WRITE_HANDLER( qsound_data_l_w )
  219. {
  220.     qsound_data=(qsound_data&0xff00)|data;
  221. }
  222.  
  223. WRITE_HANDLER( qsound_cmd_w )
  224. {
  225.     qsound_set_command(data, qsound_data);
  226. }
  227.  
  228. READ_HANDLER( qsound_status_r )
  229. {
  230.     /* Port ready bit (0x80 if ready) */
  231.     return 0x80;
  232. }
  233.  
  234. void qsound_set_command(int data, int value)
  235. {
  236.     int ch=0,reg=0;
  237.     if (data < 0x80)
  238.     {
  239.         ch=data>>3;
  240.         reg=data & 0x07;
  241.     }
  242.     else
  243.     {
  244.         if (data < 0x90)
  245.         {
  246.             ch=data-0x80;
  247.             reg=8;
  248.         }
  249.         else
  250.         {
  251.             if (data >= 0xba && data < 0xca)
  252.             {
  253.                 ch=data-0xba;
  254.                 reg=9;
  255.             }
  256.             else
  257.             {
  258.                 /* Unknown registers */
  259.                 ch=99;
  260.                 reg=99;
  261.             }
  262.         }
  263.     }
  264.  
  265.     switch (reg)
  266.     {
  267.         case 0: /* Bank */
  268.             ch=(ch+1)&0x0f;    /* strange ... */
  269.             qsound_channel[ch].bank=(value&0x7f)<<16;
  270.             qsound_channel[ch].bank /= LENGTH_DIV;
  271. #ifdef MAME_DEBUG
  272.             if (!value & 0x8000)
  273.             {
  274.                 char baf[40];
  275.                 sprintf(baf,"Register3=%04x",value);
  276.                 usrintf_showmessage(baf);
  277.             }
  278. #endif
  279.  
  280.             break;
  281.         case 1: /* start */
  282.             qsound_channel[ch].address=value;
  283.             qsound_channel[ch].address/=LENGTH_DIV;
  284.             break;
  285.         case 2: /* pitch */
  286. #if QSOUND_DRIVER1
  287.             qsound_channel[ch].pitch=(long)
  288.                     ((float)value * qsound_frq_ratio );
  289.             qsound_channel[ch].pitch/=LENGTH_DIV;
  290. #else
  291.             qsound_channel[ch].factor=((float) (value*(6/LENGTH_DIV)) /
  292.                                       (float) Machine->sample_rate)*256.0;
  293.  
  294. #endif
  295.             if (!value)
  296.             {
  297.                 /* Key off */
  298.                 qsound_channel[ch].key=0;
  299.             }
  300.             break;
  301.         case 3: /* unknown */
  302.             qsound_channel[ch].reg3=value;
  303. #ifdef MAME_DEBUG
  304.             if (value != 0x8000)
  305.             {
  306.                 char baf[40];
  307.                 sprintf(baf,"Register3=%04x",value);
  308.                 usrintf_showmessage(baf);
  309.             }
  310. #endif
  311.             break;
  312.         case 4: /* loop offset */
  313.             qsound_channel[ch].loop=value/LENGTH_DIV;
  314.             break;
  315.         case 5: /* end */
  316.             qsound_channel[ch].end=value/LENGTH_DIV;
  317.             break;
  318.         case 6: /* master volume */
  319.             if (value==0)
  320.             {
  321.                 /* Key off */
  322.                 qsound_channel[ch].key=0;
  323.             }
  324.             else if (qsound_channel[ch].key==0)
  325.             {
  326.                 /* Key on */
  327.                 qsound_channel[ch].key=1;
  328. #if QSOUND_DRIVER1
  329.                 qsound_channel[ch].offset=0;
  330.                 qsound_channel[ch].lastdt=0;
  331. #else
  332.                 qsound_channel[ch].cursor=qsound_channel[ch].address <<8 ;
  333.                 qsound_channel[ch].buffer=qsound_sample_rom+
  334.                                          qsound_channel[ch].bank;
  335. #endif
  336.             }
  337.             qsound_channel[ch].vol=value;
  338. #if QSOUND_DRIVER2
  339.             calcula_mix(ch);
  340. #endif
  341.             break;
  342.  
  343.         case 7:  /* unused */
  344. #ifdef MAME_DEBUG
  345.             {
  346.                 char baf[40];
  347.                 sprintf(baf,"UNUSED QSOUND REG 7=%04x",value);
  348.                 usrintf_showmessage(baf);
  349.             }
  350. #endif
  351.  
  352.             break;
  353.         case 8:
  354.             {
  355. #if QSOUND_DRIVER1
  356.                int pandata=(value-0x10)&0x3f;
  357.                if (pandata > 32)
  358.                {
  359.                     pandata=32;
  360.                }
  361.                qsound_channel[ch].lvol=qsound_pan_table[pandata];
  362.                qsound_channel[ch].rvol=qsound_pan_table[32-pandata];
  363. #endif
  364.                qsound_channel[ch].pan = value;
  365. #if QSOUND_DRIVER2
  366.                calcula_mix(ch);
  367. #endif
  368.             }
  369.             break;
  370.          case 9:
  371.             qsound_channel[ch].reg9=value;
  372. /*
  373. #ifdef MAME_DEBUG
  374.             {
  375.                 char baf[40];
  376.                 sprintf(baf,"QSOUND REG 9=%04x",value);
  377.                 usrintf_showmessage(baf);
  378.             }
  379. #endif
  380. */
  381.             break;
  382.     }
  383. #if LOG_QSOUND
  384.     logerror("QSOUND WRITE %02x CH%02d-R%02d =%04x\n", data, ch, reg, value);
  385. #endif
  386. }
  387.  
  388. #if QSOUND_DRIVER1
  389.  
  390. /* Driver 1 - based on the Amuse source */
  391.  
  392. void qsound_update( int num, INT16 **buffer, int length )
  393. {
  394.     int i,j;
  395.     int rvol, lvol, count;
  396.     struct QSOUND_CHANNEL *pC=&qsound_channel[0];
  397.     QSOUND_SRC_SAMPLE * pST;
  398.     QSOUND_SAMPLE  *datap[2];
  399.  
  400.     if (Machine->sample_rate == 0) return;
  401.  
  402.     datap[0] = buffer[0];
  403.     datap[1] = buffer[1];
  404.     memset( datap[0], 0x00, length * sizeof(QSOUND_SAMPLE) );
  405.     memset( datap[1], 0x00, length * sizeof(QSOUND_SAMPLE) );
  406.  
  407.     for (i=0; i<QSOUND_CHANNELS; i++)
  408.     {
  409.         if (pC->key)
  410.         {
  411.             QSOUND_SAMPLE *pOutL=datap[0];
  412.             QSOUND_SAMPLE *pOutR=datap[1];
  413.             pST=qsound_sample_rom+pC->bank;
  414.             rvol=(pC->rvol*pC->vol)>>(8*LENGTH_DIV);
  415.             lvol=(pC->lvol*pC->vol)>>(8*LENGTH_DIV);
  416.  
  417.             for (j=length-1; j>=0; j--)
  418.             {
  419.                 count=(pC->offset)>>16;
  420.                 pC->offset &= 0xffff;
  421.                 if (count)
  422.                 {
  423.                     pC->address += count;
  424.                     if (pC->address >= pC->end)
  425.                     {
  426.                         if (!pC->loop)
  427.                         {
  428.                             /* Reached the end of a non-looped sample */
  429.                             pC->key=0;
  430.                             break;
  431.                         }
  432.                         /* Reached the end, restart the loop */
  433.                         pC->address = (pC->end - pC->loop) & 0xffff;
  434.                     }
  435.                     pC->lastdt=pST[pC->address];
  436.                 }
  437.  
  438.                 (*pOutL) += ((pC->lastdt  * lvol) >> 6);
  439.                 (*pOutR) += ((pC->lastdt  * rvol) >> 6);
  440.                 pOutL++;
  441.                 pOutR++;
  442.                 pC->offset += pC->pitch;
  443.             }
  444.         }
  445.         pC++;
  446.     }
  447.  
  448. #if LOG_WAVE
  449.     fwrite(datap[0], length*sizeof(QSOUND_SAMPLE), 1, fpRawDataL);
  450.     fwrite(datap[1], length*sizeof(QSOUND_SAMPLE), 1, fpRawDataR);
  451. #endif
  452. }
  453.  
  454. #else
  455.  
  456. /* ----------------------------------------------------------------
  457.         QSound Sample Mixer (Slow)
  458.         Miguel Angel Horna mahorna@teleline.es
  459.  
  460.  ------------------------------------------------------------------ */
  461.  
  462.  
  463. void calcula_mix(int channel)
  464. {
  465.     int factl,factr;
  466.     struct QSOUND_CHANNEL *pC=&qsound_channel[channel];
  467.     int vol=pC->vol>>5;
  468.     int pan=((pC->pan&0xFF)-0x10)<<3;
  469.     pC->mixl=vol;
  470.     pC->mixr=vol;
  471.     factr=pan;
  472.     factl=255-factr;
  473.     pC->mixl=(pC->mixl * factl)>>8;
  474.     pC->mixr=(pC->mixr * factr)>>8;
  475. #if QSOUND_8BIT_SAMPLES
  476.     pC->mixl<<=8;
  477.     pC->mixr<<=8;
  478. #endif
  479. }
  480.  
  481. void qsound_update(int num,void **buffer,int length)
  482. {
  483.     int i,j;
  484.     QSOUND_SAMPLE *bufL,*bufR, sample;
  485.     struct QSOUND_CHANNEL *pC=qsound_channel;
  486.  
  487.     memset( buffer[0], 0x00, length * sizeof(QSOUND_SAMPLE) );
  488.     memset( buffer[1], 0x00, length * sizeof(QSOUND_SAMPLE) );
  489.  
  490.     for(j=0;j<QSOUND_CHANNELS;++j)
  491.     {
  492.           bufL=(QSOUND_SAMPLE *) buffer[0];
  493.           bufR=(QSOUND_SAMPLE *) buffer[1];
  494.           if(pC->key)
  495.           {
  496.                 for(i=0;i<length;++i)
  497.                 {
  498.                            int pos=pC->cursor>>8;
  499.                            if(pos!=pC->lpos)    /*next sample*/
  500.                            {
  501.                                 sample=pC->buffer[pos];
  502.                                 pC->lastsaml=(sample*pC->mixl)>>8;
  503.                                 pC->lastsamr=(sample*pC->mixr)>>8;
  504.                                 pC->lpos=pos;
  505.                            }
  506.                            (*bufL++)+=pC->lastsaml;
  507.                            (*bufR++)+=pC->lastsamr;
  508.                            pC->cursor+=pC->factor;
  509.                            if(pC->loop && (pC->cursor>>8) > pC->end)
  510.                            {
  511.                                  pC->cursor=(pC->end-pC->loop)<<8;
  512.                            }
  513.                            else if((pC->cursor>>8) > pC->end)
  514.                                    pC->key=0;
  515.                  }
  516.           }
  517.           pC++;
  518.      }
  519. }
  520. #endif
  521.  
  522.  
  523. /**************** end of file ****************/
  524.